package com.hulk.dryad.manage.framework.tenant;

import cn.hutool.core.util.StrUtil;

import com.hulk.dryad.common.constant.CommonConstants;
import com.hulk.dryad.common.constant.enums.BEC;
import com.hulk.dryad.manage.provider.cache.SysTenantCache;
import com.hulk.dryad.manage.security.component.PermitAllSecurityUrlProperties;
import com.hulk.dryad.persistence.entity.SysTenantModel;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.stream.Stream;

/**
 * @author hulk
 * @date 2020/9/13
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(PermitAllSecurityUrlProperties.class)
@RequiredArgsConstructor
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TenantContextHolderFilter extends GenericFilterBean {

  private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

  @Value("${spring.datasource.dynamic.primary:DB_0}")
  private String primary;

  private final PermitAllSecurityUrlProperties permitAllSecurityUrlProperties;

  private final SysTenantCache sysTenantCache;

  @Override
  @SneakyThrows
  public void doFilter(
      ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;
    String uri = request.getRequestURI();

    if (Stream.of(permitAllSecurityUrlProperties.getIgnoring().toArray(new String[0])).anyMatch(tenantUri -> PATH_MATCHER.match(tenantUri, uri))) {
      log.debug("请求URI,[{}] http请求header不包含TENANT-ID信息,不需要获取租户信息.", uri);
    } else {
      String tenantId = request.getHeader(CommonConstants.TENANT_ID);
      log.debug("获取header中的租户ID为:[{}]", tenantId);
      String paramTenantId = request.getParameter(CommonConstants.TENANT_ID);
      log.debug("获取Parameter中的租户ID为:[{}]", paramTenantId);
      String datasource;
      if (StrUtil.isNotBlank(tenantId)) {
        SysTenantModel model = sysTenantCache.getTenant(tenantId);
        datasource = model == null ? primary : model.getDatasource();
      } else if (StrUtil.isNotBlank(paramTenantId)) {
        SysTenantModel model = sysTenantCache.getTenant(paramTenantId);
        datasource = model == null ? primary : model.getDatasource();
      } else {
        datasource = primary;
        TenantContextHolder.setTenantId(datasource);
        log.warn("请求URI: [{}],错误信息:  [{}]", uri, BEC.E_1005.toString());
      }
      TenantContextHolder.setTenantId(datasource);
      request.getSession().setAttribute(CommonConstants.TENANT_ID, datasource);
    }
    filterChain.doFilter(request, response);
    TenantContextHolder.clear();
  }
}
